package com.junxonline.plat.service.role.impl;

import com.junxonline.plat.dao.model.Menu;
import com.junxonline.plat.dao.model.Role;
import com.junxonline.common.dao.pojo.JsTree;
import com.junxonline.plat.dao.repository.MenuRepository;
import com.junxonline.plat.dao.repository.RoleRepository;
import com.junxonline.plat.dao.vo.PageVO;
import com.junxonline.plat.dao.vo.QueryRoleVO;
import com.junxonline.plat.dao.vo.RoleVO;
import com.junxonline.common.util.CommonUtils;
import com.junxonline.plat.service.role.RoleService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class RoleServiceImpl implements RoleService {

    private Logger logger = LogManager.getLogger();

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private MenuRepository menuRepository;

    /**
     * 获取角色树数据
     *
     * @return
     */
    @Override
    public List<JsTree> getRoleTree() {

        List<JsTree> jsTrees = new ArrayList<>();

        // 获取所有的菜单数据
        List<Role> roles = roleRepository.findAll(new Sort(Sort.Direction.ASC, "roleSort"));

        // 构建菜单树
        for (Role role : roles) {
            JsTree jsTree = new JsTree();
            jsTree.setId(role.getRoleId().toString());
            jsTree.setParent("#");
            jsTree.setText(role.getRoleName());
            jsTree.setIcon("fa fa-user icon-state-default");

            jsTrees.add(jsTree);
        }

        return jsTrees;
    }

    /**
     * 获取角色数据
     *
     * @param vo
     * @return
     */
    @Override
    public Role getRole(QueryRoleVO vo) {

        Role role = roleRepository.findByRoleId(vo.getRoleId());

        return role;
    }

    /**
     * 筛选查询角色
     *
     * @param pageVO
     * @param vo
     * @return
     */
    @Override
    public PageVO queryRole(PageVO pageVO, QueryRoleVO vo) {

        PageRequest pageRequest = PageRequest.of(pageVO.getPage() - 1, pageVO.getLimit(), new Sort(Sort.Direction.ASC, "roleSort"));

        Page<Role> page = roleRepository.findAll(new Specification<Role>() {
            @Override
            public Predicate toPredicate(Root<Role> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                List<Predicate> params = new ArrayList<>();
                String roleKey = vo.getRoleKey();
                String roleName = vo.getRoleName();
                Integer roleStatus = vo.getRoleStatus();

                if (CommonUtils.isNotEmpty(roleKey)) {
                    params.add(criteriaBuilder.like(root.get("roleKey"), "%" + roleKey + "%"));
                }

                if (CommonUtils.isNotEmpty(roleName)) {
                    params.add(criteriaBuilder.like(root.get("roleName"), "%" + roleName + "%"));
                }

                if (CommonUtils.isNotEmpty(roleStatus)) {
                    params.add(criteriaBuilder.equal(root.get("roleStatus"), roleStatus));
                }

                return criteriaBuilder.and(params.toArray(new Predicate[params.size()]));
            }
        }, pageRequest);

        List<Role> roles = page.getContent();

        for (Role role : roles) {

            // 替换角色状态
            switch (role.getRoleStatus()) {
                case 0:
                    role.setRoleStatusString("<span class=\"layui-badge layui-bg-green\">启用</span>");
                    break;
                case 1:
                    role.setRoleStatusString("<span class=\"layui-badge\">禁用</span>");
                    break;
                default:
                    break;
            }

        }

        pageVO.setTotal(page.getTotalElements());
        pageVO.setData(roles);

        return pageVO;

    }

    /**
     * 添加角色
     *
     * @param vo
     * @return
     */
    @Override
    public boolean addRole(RoleVO vo) {

        Role role = new Role();
        role.setRoleId(vo.getRoleId());
        role.setRoleKey(vo.getRoleKey());
        role.setRoleName(vo.getRoleName());
        role.setRoleSort(vo.getRoleSort());
        role.setDescription(vo.getDescription());
        role.setRoleStatus(vo.getRoleStatus());

        roleRepository.save(role);

        return true;
    }

    /**
     * 修改角色
     *
     * @param vo
     * @return
     */
    @Override
    public boolean editRole(RoleVO vo) {

        Role role = roleRepository.findByRoleId(vo.getRoleId());

        role.setRoleId(vo.getRoleId());
        role.setRoleKey(vo.getRoleKey());
        role.setRoleName(vo.getRoleName());
        role.setRoleSort(vo.getRoleSort());
        role.setDescription(vo.getDescription());
        role.setRoleStatus(vo.getRoleStatus());

        roleRepository.save(role);

        return true;
    }

    /**
     * 删除角色
     *
     * @param roleIds
     * @return
     */
    @Override
    public boolean delRole(Long[] roleIds) {

        List<Role> roles = roleRepository.findByRoleIdIn(roleIds);

        for (Role role : roles) {

            List<Menu> menus = role.getMenus();

            // 删除与该角色相关联的中间表的所有菜单数据
            for (Menu menu : menus) {
                Long menuId = menu.getMenuId();
                Long roleId = role.getRoleId();
                roleRepository.deleteRoleMenuIn(menuId, roleId);
            }

            List<Map<String, BigInteger>> userIds = roleRepository.findUserRolesByRoleId(role.getRoleId());

            // 删除与该角色相关联的中间表的所有用户数据
            for (Map<String, BigInteger> userRole : userIds) {
                Long userId = userRole.get("user_id").longValue();
                Long roleId = userRole.get("role_id").longValue();
                roleRepository.deleteUserRoleIn(userId, roleId);
            }

            // 再删除角色
            roleRepository.delete(role);
        }


        return true;
    }

    /**
     * 设置权限
     *
     * @param roleId
     * @param menuIds
     * @return
     */
    @Override
    public boolean setPermission(Long roleId, Long[] menuIds) {

        // 先校验菜单id集合
        List<Menu> menus = menuRepository.findByMenuIdIn(menuIds);

        // 校验角色id
        Role role = roleRepository.findByRoleId(roleId);

        // 删除与该角色关联的所有菜单数据
        List<Menu> deleteMenus = role.getMenus();
        for (Menu menu : deleteMenus) {
            Long menuId = menu.getMenuId();
            roleRepository.deleteRoleMenuIn(menuId, role.getRoleId());
        }

        // 再添加新的菜单数据
        for (Menu menu : menus) {
            Long menuId = menu.getMenuId();
            roleRepository.saveRoleMenuIn(menuId, role.getRoleId());
        }

        return true;
    }

}
